/*
 * Lapack.cs
 *
 * LAPACK provider for AMD's ACML compiled with Intel's FORTRAN compiler.
 *
 * Copyright (c) 2006, dnAnalytics. All rights reserved.
 */

using System;
using dnAnalytics.LinearAlgebra.Native;
using dnAnalytics.Math;

namespace dnAnalytics.LinearAlgebra.Native.Acml
{
    /// <summary>
    /// Summary description for AcmlIFort Lapack.
    /// </summary>
    internal sealed class LapackIFort : ILapack
    {
        private static readonly ILapack instance = new LapackIFort();

        private LapackIFort() { }

        #region Public Members

        public static ILapack Instance
        {
            get { return instance; }
        }

        public int Dgeqp3(int m, int n, double[] a, int lda, int[] jpvt, double[] tau)
        {
            double[] work = new double[1];
            int len = -1;
            int info = 0;
            SafeNativeMethods.DGEQP3(ref m, ref n, a, ref lda, jpvt, tau, work, ref len, ref info);
            len = (int)work[0];
            work = new double[len];
            SafeNativeMethods.DGEQP3(ref m, ref n, a, ref lda, jpvt, tau, work, ref len, ref info);
            return info;
        }

        public int Dgeqp3(int m, int n, double[] a, int lda, int[] jpvt, double[] tau, double[] work)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.DGEQP3(ref m, ref n, a, ref lda, jpvt, tau, work, ref len, ref info);
            return info;
        }

        public int Dgesvd(char jobu, char jobvt, int m, int n, double[] a, int lda, double[] s, double[] u, int ldu, double[] vt, int ldvt)
        {
            double[] work = new double[1];
            int len = -1;
            int info = 0;
            SafeNativeMethods.DGESVD(ref jobu, ref jobvt, ref m, ref n, a, ref lda, s, u, ref ldu, vt, ref ldvt, work, ref len, ref info, 1, 1);
            len = (int)work[0];
            work = new double[len];
            SafeNativeMethods.DGESVD(ref jobu, ref jobvt, ref m, ref n, a, ref lda, s, u, ref ldu, vt, ref ldvt, work, ref len, ref info, 1, 1);
            return info;
        }

        public int Dgesvd(char jobu, char jobvt, int m, int n, double[] a, int lda, double[] s, double[] u, int ldu, double[] vt, int ldvt, double[] work)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.DGESVD(ref jobu, ref jobvt, ref m, ref n, a, ref lda, s, u, ref ldu, vt, ref ldvt, work, ref len, ref info, 1, 1);
            return info;
        }

        public int Dgetrf(int m, int n, double[] a, int lda, out int[] ipiv)
        {
            int info = 0;
            ipiv = new int[m];
            SafeNativeMethods.DGETRF(ref m, ref n, a, ref lda, ipiv, ref info);
            return info;
        }

        public int Dgetri(int n, double[] a, int lda, int[] ipiv)
        {
            double[] work = new double[1];
            int len = -1;
            int info = 0;
            SafeNativeMethods.DGETRI(ref n, a, ref lda, ipiv, work, ref len, ref info);
            len = (int)work[0];
            work = new double[len];
            SafeNativeMethods.DGETRI(ref n, a, ref lda, ipiv, work, ref len, ref info);
            return info;
        }

        public int Dgetri(int n, double[] a, int lda, int[] ipiv, double[] work)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.DGETRI(ref n, a, ref lda, ipiv, work, ref len, ref info);
            return info;
        }

        public int Dgetrs(char trans, int n, int nrhs, double[] a, int lda, int[] ipiv, double[] b, int ldb)
        {
            int info = 0;
            SafeNativeMethods.DGETRS(ref trans, ref n, ref nrhs, a, ref lda, ipiv, b, ref ldb, ref info, 1);
            return info;
        }

        public int Dorgqr(int m, int n, int k, double[] a, int lda, double[] tau)
        {
            double[] work = new double[1];
            int len = -1;
            int info = 0;
            SafeNativeMethods.DORGQR(ref m, ref n, ref k, a, ref lda, tau, work, ref len, ref info);
            len = (int)work[0];
            work = new double[len];
            SafeNativeMethods.DORGQR(ref m, ref n, ref k, a, ref lda, tau, work, ref len, ref info);
            return info;
        }

        public int Dorgqr(int m, int n, int k, double[] a, int lda, double[] tau, double[] work)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.DORGQR(ref m, ref n, ref k, a, ref lda, tau, work, ref len, ref info);
            return info;
        }

        public int Dormqr(char side, char trans, int m, int n, int k, double[] a, int lda, double[] tau, double[] c, int ldc)
        {
            double[] work = new double[1];
            int len = -1;
            int info = 0;
            SafeNativeMethods.DORMQR(ref side, ref trans, ref m, ref n, ref k, a, ref lda, tau, c, ref ldc, work, ref len, ref info, 1, 1);
            len = (int)work[0];
            work = new double[len];
            SafeNativeMethods.DORMQR(ref side, ref trans, ref m, ref n, ref k, a, ref lda, tau, c, ref ldc, work, ref len, ref info, 1, 1);
            return info;
        }

        public int Dormqr(char side, char trans, int m, int n, int k, double[] a, int lda, double[] tau, double[] c, int ldc, double[] work)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.DORMQR(ref side, ref trans, ref m, ref n, ref k, a, ref lda, tau, c, ref ldc, work, ref len, ref info, 1, 1);
            return info;
        }

        public int Dpotrf(char uplo, int n, double[] a, int lda)
        {
            int info = 0;
            SafeNativeMethods.DPOTRF(ref uplo, ref n, a, ref lda, ref info, 1);
            return info;
        }

        public int Dpotri(char uplo, int n, double[] a, int lda)
        {
            int info = 0;
            SafeNativeMethods.DPOTRI(ref uplo, ref n, a, ref lda, ref info, 1);
            return info;
        }

        public int Dpotrs(char uplo, int n, int nrhs, double[] a, int lda, double[] b, int ldb)
        {
            int info = 0;
            SafeNativeMethods.DPOTRS(ref uplo, ref n, ref nrhs, a, ref lda, b, ref ldb, ref info, 1);
            return info;
        }

        public int Zgeqp3(int m, int n, Complex[] a, int lda, int[] jpvt, Complex[] tau)
        {
            Complex[] work = new Complex[1];
            double[] rwork = new double[System.Math.Max(1, 2 * n)];
            int len = -1;
            int info = 0;
            SafeNativeMethods.ZGEQP3(ref m, ref n, a, ref lda, jpvt, tau, work, ref len, rwork, ref info);
            len = (int)work[0].Real;
            work = new Complex[len];
            SafeNativeMethods.ZGEQP3(ref m, ref n, a, ref lda, jpvt, tau, work, ref len, rwork, ref info);
            return info;
        }

        public int Zgeqp3(int m, int n, Complex[] a, int lda, int[] jpvt, Complex[] tau, Complex[] work, double[] rwork)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.ZGEQP3(ref m, ref n, a, ref lda, jpvt, tau, work, ref len, rwork, ref info);
            return info;
        }

        public int Zgetrf(int m, int n, Complex[] a, int lda, out int[] ipiv)
        {
            int info = 0;
            ipiv = new int[m];
            SafeNativeMethods.ZGETRF(ref m, ref n, a, ref lda, ipiv, ref info);
            return info;
        }

        public int Zgetri(int n, Complex[] a, int lda, int[] ipiv)
        {
            Complex[] work = new Complex[1];
            int len = -1;
            int info = 0;
            SafeNativeMethods.ZGETRI(ref n, a, ref lda, ipiv, work, ref len, ref info);
            len = (int)work[0].Real;
            work = new Complex[len];
            SafeNativeMethods.ZGETRI(ref n, a, ref lda, ipiv, work, ref len, ref info);
            return info;
        }

        public int Zgetri(int n, Complex[] a, int lda, int[] ipiv, Complex[] work)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.ZGETRI(ref n, a, ref lda, ipiv, work, ref len, ref info);
            return info;
        }

        public int Zgetrs(char trans, int n, int nrhs, Complex[] a, int lda, int[] ipiv, Complex[] b, int ldb)
        {
            int info = 0;
            SafeNativeMethods.ZGETRS(ref trans, ref n, ref nrhs, a, ref lda, ipiv, b, ref ldb, ref info, 1);
            return info;
        }

        public int Zpotrf(char uplo, int n, Complex[] a, int lda)
        {
            int info = 0;
            SafeNativeMethods.ZPOTRF(ref uplo, ref n, a, ref lda, ref info, 1);
            return info;
        }

        public int Zpotri(char uplo, int n, Complex[] a, int lda)
        {
            int info = 0;
            SafeNativeMethods.ZPOTRI(ref uplo, ref n, a, ref lda, ref info, 1);
            return info;
        }

        public int Zpotrs(char uplo, int n, int nrhs, Complex[] a, int lda, Complex[] b, int ldb)
        {
            int info = 0;
            SafeNativeMethods.ZPOTRS(ref uplo, ref n, ref nrhs, a, ref lda, b, ref ldb, ref info, 1);
            return info;
        }

        public int Zungqr(int m, int n, int k, Complex[] a, int lda, Complex[] tau)
        {
            Complex[] work = new Complex[1];
            int len = -1;
            int info = 0;
            SafeNativeMethods.ZUNGQR(ref m, ref n, ref k, a, ref lda, tau, work, ref len, ref info);
            len = (int)work[0].Real;
            work = new Complex[len];
            SafeNativeMethods.ZUNGQR(ref m, ref n, ref k, a, ref lda, tau, work, ref len, ref info);
            return info;
        }

        public int Zungqr(int m, int n, int k, Complex[] a, int lda, Complex[] tau, Complex[] work)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.ZUNGQR(ref m, ref n, ref k, a, ref lda, tau, work, ref len, ref info);
            return info;
        }

        public int Zunmqr(char side, char trans, int m, int n, int k, Complex[] a, int lda, Complex[] tau, Complex[] c, int ldc)
        {
            Complex[] work = new Complex[1];
            int len = -1;
            int info = 0;
            SafeNativeMethods.ZUNMQR(ref side, ref trans, ref m, ref n, ref k, a, ref lda, tau, c, ref ldc, work, ref len, ref info, 1, 1);
            len = (int)work[0].Real;
            work = new Complex[len];
            SafeNativeMethods.ZUNMQR(ref side, ref trans, ref m, ref n, ref k, a, ref lda, tau, c, ref ldc, work, ref len, ref info, 1, 1);
            return info;
        }

        public int Zunmqr(char side, char trans, int m, int n, int k, Complex[] a, int lda, Complex[] tau, Complex[] c, int ldc, Complex[] work)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.ZUNMQR(ref side, ref trans, ref m, ref n, ref k, a, ref lda, tau, c, ref ldc, work, ref len, ref info, 1, 1);
            return info;
        }

        public int Zgesvd(char jobu, char jobvt, int m, int n, Complex[] a, int lda, double[] s, Complex[] u, int ldu, Complex[] vt, int ldvt)
        {
            Complex[] work = new Complex[1];
            double[] rwork = new double[System.Math.Max(1, 5 * System.Math.Min(m, n))];
            int len = -1;
            int info = 0;
            SafeNativeMethods.ZGESVD(ref jobu, ref jobvt, ref m, ref n, a, ref lda, s, u, ref ldu, vt, ref ldvt, work, ref len, rwork, ref info, 1, 1);
            len = (int)work[0].Real;
            work = new Complex[len];
            SafeNativeMethods.ZGESVD(ref jobu, ref jobvt, ref m, ref n, a, ref lda, s, u, ref ldu, vt, ref ldvt, work, ref len, rwork, ref info, 1, 1);
            return info;
        }

        public int Zgesvd(char jobu, char jobvt, int m, int n, Complex[] a, int lda, double[] s, Complex[] u, int ldu, Complex[] vt, int ldvt, Complex[] work, double[] rwork)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.ZGESVD(ref jobu, ref jobvt, ref m, ref n, a, ref lda, s, u, ref ldu, vt, ref ldvt, work, ref len, rwork, ref info, 1, 1);
            return info;
        }

        public int Dgels(char trans, int m, int n, int nrhs, double[] a, int lda, double[] b, int ldb)
        {
            double[] work = new double[1];
            int len = -1;
            int info = 0;
            SafeNativeMethods.DGELS(ref trans, ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, work, ref len, ref info, 1);
            len = (int)work[0];
            work = new double[len];
            SafeNativeMethods.DGELS(ref trans, ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, work, ref len, ref info, 1);
            return info;
        }

        public int Dgels(char trans, int m, int n, int nrhs, double[] a, int lda, double[] b, int ldb, double[] work)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.DGELS(ref trans, ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, work, ref len, ref info, 1);
            return info;
        }

        public int Zgels(char trans, int m, int n, int nrhs, Complex[] a, int lda, Complex[] b, int ldb)
        {
            Complex[] work = new Complex[1];
            int len = -1;
            int info = 0;
            SafeNativeMethods.ZGELS(ref trans, ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, work, ref len, ref info, 1);
            len = (int)work[0].Real;
            work = new Complex[len];
            SafeNativeMethods.ZGELS(ref trans, ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, work, ref len, ref info, 1);
            return info;
        }

        public int Zgels(char trans, int m, int n, int nrhs, Complex[] a, int lda, Complex[] b, int ldb, Complex[] work)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.ZGELS(ref trans, ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, work, ref len, ref info, 1);
            return info;
        }

        public int Dgelss(int m, int n, int nrhs, double[] a, int lda, double[] b, int ldb, out double[] s, ref int rank)
        {
            double rcond = -1;
            s = new double[System.Math.Min(m, n)];
            double[] work = new double[1];
            int len = -1;
            int info = 0;
            SafeNativeMethods.DGELSS(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, s, ref rcond, ref rank, work, ref len, ref info);
            len = (int)work[0];
            work = new double[len];
            SafeNativeMethods.DGELSS(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, s, ref rcond, ref rank, work, ref len, ref info);
            return info;
        }

        public int Dgelss(int m, int n, int nrhs, double[] a, int lda, double[] b, int ldb, out double[] s, double rcond, ref int rank, double[] work)
        {
            int info = 0;
            int len = work.Length;
            s = new double[System.Math.Min(m, n)];
            SafeNativeMethods.DGELSS(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, s, ref rcond, ref rank, work, ref len, ref info);
            return info;
        }

        public int Zgelss(int m, int n, int nrhs, Complex[] a, int lda, Complex[] b, int ldb, out double[] s, ref int rank)
        {
            double rcond = -1;
            s = new double[System.Math.Min(m, n)];
            Complex[] work = new Complex[1];
            double[] rwork = new double[System.Math.Max(1, 5 * System.Math.Min(m, n))];
            int len = -1;
            int info = 0;
            SafeNativeMethods.ZGELSS(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, s, ref rcond, ref rank, work, ref len, rwork, ref info);
            len = (int)work[0].Real;
            work = new Complex[len];
            SafeNativeMethods.ZGELSS(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, s, ref rcond, ref rank, work, ref len, rwork, ref info);
            return info;
        }

        public int Zgelss(int m, int n, int nrhs, Complex[] a, int lda, Complex[] b, int ldb, out double[] s, double rcond, ref int rank, Complex[] work, double[] rwork)
        {
            int info = 0;
            int len = work.Length;
            s = new double[System.Math.Min(m, n)];
            SafeNativeMethods.ZGELSS(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, s, ref rcond, ref rank, work, ref len, rwork, ref info);
            return info;
        }

        public int Dgelsy(int m, int n, int nrhs, double[] a, int lda, double[] b, int ldb, int[] jpvt, double rcond, ref int rank)
        {
            double[] work = new double[1];
            int len = -1;
            int info = 0;
            SafeNativeMethods.DGELSY(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, jpvt, ref rcond, ref rank, work, ref len, ref info);
            len = (int)work[0];
            work = new double[len];
            SafeNativeMethods.DGELSY(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, jpvt, ref rcond, ref rank, work, ref len, ref info);
            return info;
        }

        public int Dgelsy(int m, int n, int nrhs, double[] a, int lda, double[] b, int ldb, int[] jpvt, double rcond, ref int rank, double[] work)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.DGELSY(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, jpvt, ref rcond, ref rank, work, ref len, ref info);
            return info;
        }

        public int Zgelsy(int m, int n, int nrhs, Complex[] a, int lda, Complex[] b, int ldb, int[] jpvt, double rcond, ref int rank)
        {
            Complex[] work = new Complex[1];
            double[] rwork = new double[System.Math.Max(1, 2 * n)];
            int len = -1;
            int info = 0;
            SafeNativeMethods.ZGELSY(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, jpvt, ref rcond, ref rank, work, ref len, rwork, ref info);
            len = (int)work[0].Real;
            work = new Complex[len];
            SafeNativeMethods.ZGELSY(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, jpvt, ref rcond, ref rank, work, ref len, rwork, ref info);
            return info;
        }

        public int Zgelsy(int m, int n, int nrhs, Complex[] a, int lda, Complex[] b, int ldb, int[] jpvt, double rcond, ref int rank, Complex[] work, double[] rwork)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.ZGELSY(ref m, ref n, ref nrhs, a, ref lda, b, ref ldb, jpvt, ref rcond, ref rank, work, ref len, rwork, ref info);
            return info;
        }

        public double Dlange(char norm, int m, int n, double[] a, int lda)
        {
            double[] work = new double[m];
            return Dlange(norm, m, n, a, lda, work);
        }

        public double Dlange(char norm, int m, int n, double[] a, int lda, double[] work)
        {
            return SafeNativeMethods.DLANGE(ref norm, ref m, ref n, a, ref lda, work, 1);
        }

        public double Zlange(char norm, int m, int n, Complex[] a, int lda)
        {
            double[] work = new double[m];
            return Zlange(norm, m, n, a, lda, work);
        }

        public double Zlange(char norm, int m, int n, Complex[] a, int lda, double[] work)
        {
            return SafeNativeMethods.ZLANGE(ref norm, ref m, ref n, a, ref lda, work, 1);
        }

        public int Dgecon(char norm, int n, double[] a, int lda, double anorm, ref double rcond)
        {
            double[] work = new double[System.Math.Max(1, 4 * n)];
            int[] iwork = new int[System.Math.Max(1, n)];
            return Dgecon(norm, n, a, lda, anorm, ref rcond, work, iwork);
        }

        public int Dgecon(char norm, int n, double[] a, int lda, double anorm, ref double rcond, double[] work, int[] iwork)
        {
            int info = 0;
            SafeNativeMethods.DGECON(ref norm, ref n, a, ref lda, ref anorm, ref rcond, work, iwork, ref info, 1);
            return info;
        }

        public int Zgecon(char norm, int n, Complex[] a, int lda, double anorm, ref double rcond)
        {
            Complex[] work = new Complex[System.Math.Max(1, 4 * n)];
            double[] rwork = new double[System.Math.Max(1, 2 * n)];
            return Zgecon(norm, n, a, lda, anorm, ref rcond, work, rwork);
        }

        public int Zgecon(char norm, int n, Complex[] a, int lda, double anorm, ref double rcond, Complex[] work, double[] rwork)
        {
            int info = 0;
            SafeNativeMethods.ZGECON(ref norm, ref n, a, ref lda, ref anorm, ref rcond, work, rwork, ref info, 1);
            return info;
        }

        public int Ilaenv(int ispec, string name, string opts, int n1, int n2, int n3, int n4)
        {
            return SafeNativeMethods.ILAENV(ref ispec, name, opts, ref n1, ref n2, ref n3, ref n4, name.Length, opts.Length);
        }

        public int Dgeqrf(int m, int n, double[] a, int lda, double[] tau)
        {
            double[] work = new double[1];
            int len = -1;
            int info = 0;
            SafeNativeMethods.DGEQRF(ref m, ref n, a, ref lda, tau, work, ref len, ref info);
            len = (int)work[0];
            work = new double[len];
            SafeNativeMethods.DGEQRF(ref m, ref n, a, ref lda, tau, work, ref len, ref info);
            return info;
        }

        public int Dgeqrf(int m, int n, double[] a, int lda, double[] tau, double[] work)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.DGEQRF(ref m, ref n, a, ref lda, tau, work, ref len, ref info);
            return info;
        }

        public int Zgeqrf(int m, int n, Complex[] a, int lda, Complex[] tau)
        {
            Complex[] work = new Complex[1];
            int len = -1;
            int info = 0;
            SafeNativeMethods.ZGEQRF(ref m, ref n, a, ref lda, tau, work, ref len, ref info);
            len = (int)work[0].Real;
            work = new Complex[len];
            SafeNativeMethods.ZGEQRF(ref m, ref n, a, ref lda, tau, work, ref len, ref info);
            return info;
        }

        public int Zgeqrf(int m, int n, Complex[] a, int lda, Complex[] tau, Complex[] work)
        {
            int info = 0;
            int len = work.Length;
            SafeNativeMethods.ZGEQRF(ref m, ref n, a, ref lda, tau, work, ref len, ref info);
            return info;
        }
        #endregion Public Members
    }
}
